﻿using System;
using System.Collections.Generic;
using System.Drawing.Text;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using PdfLibrary;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using TtfLibrary;
using Path = System.IO.Path;

namespace WpfViewer
{
    public class PdfGraphicsWpfEnvironment : PdfGraphicsEnvironment
    {
        public Canvas Canvas;

        public PdfGraphicsWpfEnvironment()
        {
        }

        Dictionary<IPdfFont, FontFamily> fontDict = new Dictionary<IPdfFont, FontFamily>();

        private FontFamily GetFontFamily(IPdfFont pdfFont)
        {
            FontFamily result;

            if(!fontDict.TryGetValue(pdfFont, out result))
            {
                var tmpFn = Path.GetTempPath() + @"\" + Path.GetRandomFileName() + ".ttf";

                var fontContent = pdfFont.FontDescriptor.FontFile2.DecodedData;
                File.WriteAllBytes(tmpFn, fontContent);

                result = Fonts.GetFontFamilies(tmpFn).FirstOrDefault();

                if (result == null)
                {
                    try
                    {
                        var ttfFile = TtfFile.Load(new MemoryStream(fontContent));
                        TtfUtilities.FixFileForWindows(ttfFile);
                        var tmpFn2 = Path.GetTempPath() + @"\" + Path.GetRandomFileName() + ".ttf";
                        using (var file = File.Create(tmpFn2))
                            ttfFile.Save(file);

                        result = Fonts.GetFontFamilies(tmpFn2).FirstOrDefault();
                    }
                    catch
                    {
                    }
                }

                fontDict.Add(pdfFont, result);
            }

            return result;
        }

        public override void DrawString(string text)
        {
            var textbox = new TextBlock { Text = text, FontSize = this.FontSize };
            var font = GetFontFamily(Font);
            if (font != null)
                textbox.FontFamily = font;

            var mx = CurrentTextObject.TextMatrix.Clone();
            var w = CurrentTextObject.JobbraBalraMozgatas;
            mx = mx.Translate(w, 0);
            mx *= CurrentGraphicsState.CTM;

            PlaceOnCanvas(textbox, mx);

            CurrentTextObject.JobbraBalraMozgatas += textbox.DesiredSize.Width;
        }

        private int imgId = 0;
        public override void DrawImage(PdfStream imageStream)
        {
            imgId++;

            var data = imageStream.DecodedStream;

            var image = new Image { 
                Source = BitmapFrame.Create(data, BitmapCreateOptions.None, BitmapCacheOption.OnLoad), 
                Width = 1, 
                Height = 1, 
                Stretch = Stretch.Fill,
            };

            //File.WriteAllBytes(String.Format("img_{0}.jpg", imgId), imageStream.DecodedData);

            if (imageStream.dictionary.ContainsKey("SMask"))
            {
                var mask = (PdfStream)((PdfIndirectReference)imageStream.dictionary["SMask"]).ResolvedObject;

                var width = (int)((PdfNumber)mask.dictionary["Width"]).value;
                var height = (int)((PdfNumber)mask.dictionary["Height"]).value;

                byte[] oldArr = mask.DecodedData;
                var length = oldArr.Length;
                var newArr = new byte[length * 4];

                for (int i = 0; i < length; i++)
                    newArr[i*4 + 3] = oldArr[i];

                var bmp = new WriteableBitmap(width, height, 150.0, 150.0, PixelFormats.Pbgra32, null);
                bmp.WritePixels(new Int32Rect(0, 0, width, height), newArr, width * 4, 0);

                /*var enc = new PngBitmapEncoder();
                enc.Frames.Add(BitmapFrame.Create(bmp));
                using(var file = File.Create(String.Format("mask_{0}.png", imgId)))
                    enc.Save(file);*/

                image.OpacityMask = new ImageBrush(bmp);
                //image.Source = bmp;
            }

            PlaceOnCanvas(image);
        }

        public void PlaceOnCanvas(UIElement item, TransformationMatrix mx = null)
        {
            if (mx == null)
                mx = CurrentGraphicsState.CTM;
            mx = mx.Clone();

            item.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
            var size = item.DesiredSize;

            mx = mx.Translate(0, size.Height);
            var wpfMx = new MatrixTransform(ConvertMatrix(mx));
            item.RenderTransform = wpfMx;

            Canvas.SetBottom(item, 0);
            Canvas.SetLeft(item, 0);
            Canvas.Children.Add(item);
        }

        public static Matrix ConvertMatrix(TransformationMatrix mx)
        {
            return new Matrix(mx.Values[0, 0], mx.Values[0, 1], mx.Values[1, 0], mx.Values[1, 1], mx.Values[2, 0], -mx.Values[2, 1]);
        }
    }
}
